home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Font Database / FontDBaseDocument.c next >
Encoding:
Text File  |  2000-09-28  |  62.8 KB  |  2,256 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        FontDBaseDocument.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains code to union page font databases into a document database.
  6.  
  7.      Version:    Technology:    Quickdraw GX 1.1.x
  8.       
  9.      Copyright:    © 1991-1997 by Apple Computer, Inc., all rights reserved.
  10. */
  11.  
  12. // allow multiple references to single label
  13. #define resumeLabel(exception)
  14.  
  15. #include <Resources.h>
  16. #include "GXExceptions.h"
  17. #include "GXPrintingUniverse.h"
  18. #include "IOUtilities.h"
  19.  
  20. #include "FontDataBase.h"
  21. #include "FontDBasePrivate.h"
  22. #include "ImageCompression.h"
  23. #include "QuickDraw.h"
  24.  
  25. #include "string.h"
  26.  
  27. #if DEBUGLEVEL > 0
  28.         #define ASSERT(trueCondition, message)        if (!(trueCondition)) dprintf(notrace, message); else
  29.  
  30.         static void AssertNoSfntReferences(Handle fond)
  31.         {
  32.                 const short*    FAT = (const short*)((const FamRec*)*fond + 1);
  33.                 int                        FATCountBase0 = *FAT++;
  34.             
  35.                 if (FAT[pointSizeIndex] == 0)
  36.                         dprintf(notrace, "NFNT gxFont matched a FOND %08lx with a FAT entry for an sfnt", fond);
  37.         }
  38. #else
  39.         #define ASSERT(trueCondition, message)
  40.         #define AssertNoSfntReferences(fond)
  41. #endif
  42.  
  43. /************************
  44.  
  45.     CopyResourceToHandle makes a copy of a loaded resource and returns the new Handle
  46.     in the same parameter. This is called instead of DetachResource 'cause the FM
  47.     doesn't like it when you detach a font that's being used (like Geneva 9 italic)
  48.     
  49. ************************/
  50. static OSErr CopyResourceToHandle(Handle* h)
  51. {
  52.         OSErr status;
  53.         int state;
  54.         long size;
  55.         Handle newh;
  56.         
  57.         state = HGetState(*h);
  58.         HNoPurge(*h);
  59.         size = GetResourceSizeOnDisk(*h);
  60.         status = PrNewHandle(&newh, size);
  61.         HSetState(*h, state);
  62.         nrequire(status, failed_new_handle);
  63.         BlockMoveData(**h, *newh, size);
  64.         *h = newh;
  65.  
  66. failed_new_handle:
  67.         return status;
  68. }
  69.  
  70. #if !GXTOPOSTSCRIPTLIBRARY
  71.  
  72. /************************
  73.  
  74.     FDBDeleteFATEntry:
  75.  
  76.     Delete the FAT entry from the FOND, and update any offsets to reflect the new, smaller FOND.
  77.  
  78. *************************/
  79. static void FDBDeleteFATEntry(Handle fond, short FAT[])
  80. {
  81.         FamRec*        fam = (FamRec*)*fond;
  82.         short*        nextFAT = FAT + shortsInAFATRecord;
  83.  
  84.         (*(short*)(fam + 1))--;        /* reduce the FAT count */
  85.  
  86.         BlockMoveData((Ptr)nextFAT, (Ptr)FAT, NoGlueGetHandleSize(fond) - ((char*)nextFAT - (char*)fam));
  87.         if (fam->ffWTabOff)
  88.                 fam->ffWTabOff -= bytesInAFATRecord;
  89.         if (fam->ffKernOff)
  90.                 fam->ffKernOff -= bytesInAFATRecord;
  91.         if (fam->ffStylOff)
  92.                 fam->ffStylOff -= bytesInAFATRecord;
  93. }
  94.  
  95. /************************
  96.  
  97.     FDBFONDReferencesFont:
  98.  
  99.     Return a copy of the FOND (as a handle, not a resource), that has its FAT trimmed to refer to only
  100.     those strikes (sfnt, nfnt) that are needed for the list of gxFonts. Nil means we don't need the FOND.
  101.  
  102.     We remove any sfnts that are not referenced, but leave any and all nfnts, since we don't know which
  103.     were used in QD (since we don't know what point size(s) were used.
  104.     
  105.     May return fondCopy = nil, since the fonts may be application specific sfnts, and not have a corresponding
  106.     quickdraw FOND.
  107.  
  108. *************************/
  109. static OSErr FDBFONDReferencesFont(Handle fond, int fontCount, const fontSfntMap fontList[], Handle* fondCopy)
  110. {
  111.         OSErr        status = 0;
  112.         Boolean        match = false;
  113.  
  114.         *fondCopy = nil;
  115.         if (*(short*)((FamRec*)*fond + 1) < 0)                /* the FAT is empty */
  116.                 return status;
  117.  
  118.         while (fontCount-- > 0)
  119.         {        gxFontStorageTag                    storage;
  120.                 gxFontStorageReference        reference;
  121.                 gxFontFormatTag                        format;
  122.                 gxFont                                        fontID;
  123.                 
  124.                 fontID = fontList->fontID;
  125.                 storage = GXGetFont(fontID, &reference, nil);
  126.                 format = GXGetFontFormat(fontID);
  127.                 if (format == nfntFontFormatTag)
  128.                 {        FamRec fam;
  129.                         
  130.                         if (GXFindFontTableParts(fontID, 'FOND', 0, sizeof(FamRec), &fam, nil) > 0)
  131.                         {        if (fam.ffFamID == ((const FamRec*)*fond)->ffFamID)
  132.                                 {        status = CopyResourceToHandle(&fond);
  133.                                         nrequire(status, failed_copy_resource_to_handle);
  134.                                         AssertNoSfntReferences(fond);
  135.                                         *fondCopy = fond;
  136.                                         return status;
  137.                                 }
  138.                         }
  139.                 }
  140.                 else if (storage == gxResourceFontStorage)
  141.                 {        short            rsrcID;
  142.                         OSType        unusedTypeID;
  143.                         Str255        unusedName;
  144.                         short*        FAT = (short*)((const FamRec*)*fond + 1);
  145.                         int                FATCountBase0 = *FAT++;
  146.  
  147.                         GetResInfo((Handle)reference, &rsrcID, &unusedTypeID, unusedName);
  148.                         status = ResError();
  149.                         nrequire(status, failed_get_res_info);
  150.                         
  151.                         while (FATCountBase0-- >= 0)
  152.                         {        if (FAT[pointSizeIndex] == 0)
  153.                                 {        if (FAT[rsrcIDIndex] == rsrcID)
  154.                                         {        if (match == false)
  155.                                                 {        long offset = (char*)FAT - (char*)*fond;
  156.                                                         status = CopyResourceToHandle(&fond);
  157.                                                         nrequire(status, failed_copy_resource_to_handle);
  158.                                                         FAT = (short*)((char*)*fond + offset);
  159.                                                         match = true;
  160.                                                 }
  161.                                                 FAT[pointSizeIndex] = kTakeThisSfntResource;
  162.                                                 FAT[rsrcIDIndex] = fontList->newSfntRsrcID;
  163.                                                 break;
  164.                                         }
  165.                                 }
  166.                                 else if (FAT[pointSizeIndex] != kTakeThisSfntResource)
  167.                                         break;        /* stop when we've seen all the 'sfnt' resources */
  168.                                 FAT += shortsInAFATRecord;
  169.                         }
  170.                 }
  171.                 ++fontList;
  172.         }
  173.  
  174.         if (match)
  175.         {        short*        FAT = (short*)((FamRec*)*fond + 1);
  176.                 int                FATCountBase0 = *FAT++;
  177.                 long            reduce = 0;
  178.  
  179.                 while (FATCountBase0-- >= 0)
  180.                 {        if (FAT[pointSizeIndex] == 0)                /* an sfnt that we did NOT flag */
  181.                         {        
  182.                                 //dprintf(notrace, "deleting FAT [%d %d %d]", FAT[0], FAT[1], FAT[2]);
  183.                                 FDBDeleteFATEntry(fond, FAT);
  184.                                 reduce += bytesInAFATRecord;
  185.                         }
  186.                         else if (FAT[pointSizeIndex] == kTakeThisSfntResource)
  187.                         {        FAT[pointSizeIndex] = 0;                /* restore the 0-point size for 'sfnt's */
  188.                                 FAT += shortsInAFATRecord;
  189.                         }
  190.                         else
  191.                         {        ASSERT(FAT[pointSizeIndex] > 0, "assumed the was an NFNT fat");
  192.                                 break;        /* an NFNT means we're done deleting */
  193.                         }
  194.                 }
  195.                 if (reduce)
  196.                         PrSetHandleSize(fond, NoGlueGetHandleSize(fond) - reduce);
  197.                 *fondCopy = fond;
  198.         }
  199.  
  200. failed_get_res_info:
  201. failed_copy_resource_to_handle:
  202.         return status;
  203. }
  204.  
  205. /****************************
  206.  
  207.     FDBListOfReferencedFONDs:
  208.     
  209.     Takes an array of fontSfntMap records, and returns an array of FOND handles that reference
  210.     the gxFonts in the records.
  211.     
  212. ******************************/
  213. OSErr _FDBListOfReferencedFONDs(long fontCount, const fontSfntMap fontList[], long* FONDCount, Handle* FONDListPtr)
  214. {
  215.         OSErr    status;
  216.         Handle    FONDList;
  217.         int        rsrcCount, index;
  218.         
  219.         *FONDCount = 0;
  220.         rsrcCount = CountResources('FOND');
  221.         status = ResError();
  222.         nrequire(status, failed_count_resources);
  223.         status = PrNewHandle(&FONDList, rsrcCount * sizeof(Handle));    /* worst case */
  224.         nrequire(status, failed_new_handle);
  225.         
  226.         for (index = 1; index <= rsrcCount; index++)
  227.         {        Handle fond = GetIndResource('FOND', index);
  228.             
  229.                 status = ResError();
  230.                 nrequire(status, failed_get_ind_resource);
  231.                 do {
  232.                         Handle fondCopy;
  233.                         
  234.                         status = FDBFONDReferencesFont(fond, fontCount, fontList, &fondCopy);
  235.                         nrequire(status, failed_fond_references_font);
  236.                         if (fondCopy)
  237.                                 GetHandleArray(FONDList, (*FONDCount)++) = fondCopy;
  238.                 } while (fond = XGetNextFOND(fond));
  239.         }
  240.         if (*FONDCount > 0)
  241.                 PrSetHandleSize(FONDList, *FONDCount * sizeof(Handle));    /* shrink it back down */
  242.         else
  243.         {        PrDisposeHandle(FONDList);
  244.                 FONDList = nil;
  245.         }
  246.         *FONDListPtr = FONDList;
  247.         return status;
  248.  
  249. failed_get_ind_resource:
  250. failed_fond_references_font:
  251.         for (index = 0; index < *FONDCount; index++)
  252.                 PrDisposeHandle(GetHandleArray(FONDList, index));
  253.         PrDisposeHandle(FONDList);
  254. failed_new_handle:
  255. failed_count_resources:
  256.         return status;
  257. }
  258.  
  259. static OSErr WriteAndMarkPurgeable(Handle rsrc)
  260. {
  261.         check( HGetState( rsrc ) & 0x20 );
  262.         SetResAttrs(rsrc,GetResAttrs(rsrc) | resPurgeable);
  263.         WriteResource(rsrc);
  264.         return ResError();
  265. }
  266.  
  267. /****************************
  268.  
  269.     FDBAddFONDsToResourceFile:
  270.     
  271.     Takes an array of FOND handles in FONDList, and addes them to the file theFile.
  272.     It also adds any 'NFNT' and 'FONT' resources that are referenced by each FOND.
  273.     It does NOT add the 'sfnt' that are referenced, since they are assumed to have 
  274.     been previously added.
  275.     
  276. ******************************/
  277. OSErr _FDBAddFONDsToResourceFile(long FONDCount, Handle FONDList, gxSpoolFile theFile, Boolean useMessages)
  278. {
  279.         int        index;
  280.         OSErr    status;
  281.  
  282.         for (index = 0; index < FONDCount; index++)
  283.         {        const Handle    fond = GetHandleArray(FONDList, index);
  284.                 const short*    FAT = (short*)((const FamRec*)*fond + 1);
  285.                 int                        FATCountBase0 = *FAT++;
  286.     
  287.                 HLock(fond);
  288.                 while (FATCountBase0-- >= 0)
  289.                 {        if (FAT[pointSizeIndex] > 0)
  290.                         {        Handle strike;
  291.                         
  292.                                 if (!(strike = GetResource('NFNT', FAT[rsrcIDIndex])))
  293.                                         strike = GetResource('FONT', FAT[rsrcIDIndex]);
  294.                                 if (strike)
  295.                                 {        status = CopyResourceToHandle(&strike);
  296.                                         nrequire(status, failed_copy_resource_to_handle);
  297.                         
  298.                                         HNoPurge(strike);
  299.                                         if (useMessages)
  300.                                                 status = Send_GXSpoolResource(theFile, strike, 'NFNT', FAT[rsrcIDIndex]);
  301.                                         else
  302.                                                 status = FHAddResource( (TFile)theFile, strike, 'NFNT', FAT[rsrcIDIndex]);
  303.                                         nrequire(status, failed_add_resource_nfnt);
  304.                                         status = WriteAndMarkPurgeable(strike);
  305.                                         nrequire(status, failed_add_resource_nfnt);
  306.                                 }
  307.                         }
  308.                         FAT += shortsInAFATRecord;
  309.                 }
  310.                 HUnlock(fond);
  311.                 if (useMessages)
  312.                         status = Send_GXSpoolResource(theFile, fond, 'FOND', ((FamRec*)*fond)->ffFamID);
  313.                 else
  314.                         status = FHAddResource( (TFile)theFile, fond, 'FOND', ((FamRec*)*fond)->ffFamID);
  315.                 nrequire(status, failed_add_resource_fond);
  316.                 status = WriteAndMarkPurgeable(fond);
  317.                 nrequire(status, failed_add_resource_fond);
  318.         }
  319. failed_add_resource_nfnt:
  320. failed_copy_resource_to_handle:
  321. failed_add_resource_fond:
  322.         PrDisposeHandle(FONDList);
  323.         return status;
  324. }
  325.  
  326. #endif
  327.  
  328. /****************************
  329.  
  330.     FDBComputeEntrySize:
  331.     
  332.     Computes the size of the variable length poriton
  333.     of a font database entry.  This added to 
  334.     sizeof(TFDBEntry) is the total size of the 
  335.     entry
  336.     
  337. ******************************/
  338. long FDBComputeEntrySize(gxFlatFontListItem *theEntry);
  339. long FDBComputeEntrySize(gxFlatFontListItem *theEntry)
  340.     {
  341.         long        entrySize;
  342.         
  343.         entrySize = 4 * ((theEntry->length + 3) / 4) +                                                                    // the name size long alligned.
  344.             (theEntry->variationCount + 1) * (4 * ((theEntry->glyphCount + 31) / 32)) +        // All of the bit arrays (main + each variation)
  345.             theEntry->variationCount * theEntry->axisCount * sizeof(gxFontVariation);            // all of the axis values.
  346.     
  347.         return(entrySize);
  348.     
  349.     }//FDBComputeEntrySize
  350.  
  351.  
  352.  
  353. //<FF>
  354. /****************************
  355.     FDBEqualVariations:
  356.     
  357.     Test two varations for equality
  358.     
  359.     num:                number of axes
  360.     v1:                    pointer to 1st coordinates
  361.     v2:                    pointer to 2nd coordinates
  362.     
  363. ******************************/
  364. Boolean    FDBEqualVariations(long num, gxFontVariation* v1, gxFontVariation* v2);
  365. Boolean    FDBEqualVariations(long num, gxFontVariation* v1, gxFontVariation* v2)
  366.     {
  367.         register short        idx;
  368.             
  369.         for (idx = num - 1; idx >= 0; --idx) {
  370.             if ((v1->name != v2->name) || (v1->value != v2->value) ) {
  371.                 return(false);
  372.             }//end if
  373.             ++v1;
  374.             ++v2;
  375.         }//end for
  376.         return(true);    
  377.     
  378.     }//FDBEqualVariations
  379.     
  380.  
  381.  
  382.  
  383.  
  384. //<FF>
  385. /************************************************
  386.  
  387.     Function: FDBAddVariationBitPair
  388.     
  389.     Function adds a new variation/bit pair to a 
  390.     document font database entry.
  391.     
  392.     hDbase:                    handle to the document font database
  393.     entryOffset:        Offset to the entry to modify
  394.     newCoordinate:    The new coordinate to add
  395.     newBits:                The new glyph bits to add.
  396.     
  397. **************************************************/
  398. OSErr FDBAddVariationBitPair(TFontDbaseHdl hDbase, long entryOffset, gxFontVariation* newCoordinate, unsigned long* newBits);
  399. OSErr FDBAddVariationBitPair(TFontDbaseHdl hDbase, long entryOffset, gxFontVariation* newCoordinate, unsigned long* newBits)
  400.     {
  401.         OSErr                    status;
  402.         TFDBEntry            *theEntry;
  403.         long                    axisCount;
  404.         long                    glyphBitSize;
  405.         long                    oldSize, additionalSize, sizeToSlide, entrySize, offset;
  406.         unsigned char    *start;
  407.         long                    i, n;
  408.         
  409.         
  410.         //dprintf(trace, "EntryOffset: %d", entryOffset);
  411.         
  412.         theEntry = (TFDBEntry*)( (long)(*hDbase)->fontDbaseInfo + entryOffset);
  413.         axisCount = theEntry->fontInfo.axisCount;
  414.         glyphBitSize = 4 * ((theEntry->fontInfo.glyphCount + 31) / 32);
  415.         
  416.         //dprintf(trace, "axisCount: %d, glyphBitSize: %d, #instances %d", axisCount, glyphBitSize, theEntry->fontInfo.variationCount);
  417.         
  418.         /**** Grow the font database handle to accomodate the new data *****/
  419.         
  420.         oldSize = sizeof(TFontDbaseRec) + (*hDbase)->nextOffset;
  421.         additionalSize = axisCount * sizeof(gxFontVariation) + glyphBitSize;
  422.  
  423.         //dprintf(trace, "old size: %d, additinal size: %d", oldSize, additionalSize);
  424.                             
  425.         status = PrSetHandleSize((Handle)hDbase, oldSize + additionalSize);
  426.         nrequire(status, failed_SetSize);
  427.         
  428.         /****************
  429.             Now slide all entries after the one we are adding
  430.             to down to make room for new data
  431.         *****************/
  432.         
  433.         /* Compute the start address of the data to slide, theEntry + size of the entry */
  434.  
  435.         theEntry = (TFDBEntry*)( (long)(*hDbase)->fontDbaseInfo + entryOffset);
  436.  
  437.         entrySize = sizeof(TFDBEntry) + FDBComputeEntrySize(&(theEntry->fontInfo));
  438.         
  439.  
  440.         start = (unsigned char*)(theEntry) + entrySize;
  441.         
  442.         /* Slide the data */
  443.         
  444.         sizeToSlide = (*hDbase)->nextOffset - (entryOffset + entrySize);
  445.         //dprintf(trace, "entrySize: %d, sizeToSlide %d", entrySize, sizeToSlide);
  446.         if (sizeToSlide > 0)
  447.             BlockMoveData((Ptr)start, (Ptr)(start + additionalSize), sizeToSlide);
  448.                 
  449.         
  450.         /******
  451.             Now actually copy the new data into our entry
  452.         ******/
  453.         
  454.         /* Start is pointing to where to put the new data */
  455.  
  456.         theEntry->fontInfo.variationCount += 1;
  457.         
  458.         //dprintf(notrace, "newBits: %X, newCoordinate: %X", newBits, newCoordinate);
  459.         BlockMoveData((Ptr)newBits, (Ptr)start, glyphBitSize);
  460.         BlockMoveData((Ptr)newCoordinate, (Ptr)(start + glyphBitSize), axisCount * sizeof(gxFontVariation));
  461.  
  462.  
  463.         /*******
  464.             Update the offset collection:
  465.                 any entries after the current one
  466.                 must have the additionalSize added to their
  467.                 offsets stored in the collection
  468.         *******/
  469.         
  470.         n = (*hDbase)->numFonts;
  471.         for (i = 1; i <= n; ++i) {
  472.         
  473.             /** Get the offset of the next entry **/
  474.             
  475.             status = GetIndexedCollectionItem((*hDbase)->docFonts, i, nil, &offset);
  476.             nrequire(status, failed_GetItem);
  477.             
  478.             /** If the offset is greater than the entries offset then it must be updated **/
  479.             
  480.             if (offset > entryOffset) {
  481.             
  482.                 offset += additionalSize;                // update the value
  483.                 
  484.                 status = ReplaceIndexedCollectionItem((*hDbase)->docFonts, i, sizeof(long), &offset);
  485.                 nrequire(status, failed_ReplaceItem);
  486.             
  487.             }//end if
  488.         
  489.         }//end for
  490.         
  491.         /** Now update the rest of the database record **/
  492.         
  493.         (*hDbase)->nextOffset += additionalSize;                // move the next available offset
  494.                 
  495.         
  496. failed_ReplaceItem:
  497. failed_GetItem:        
  498. failed_SetSize:
  499.  
  500.         return(status);
  501.     
  502.     
  503.     }//FDBAddVariationBitPair
  504.  
  505. //<FF>
  506. /************************************************
  507.  
  508.     Function:        FDBUnionEntry
  509.     
  510.     Function unions a new page database tag (flatFontList)
  511.     with the one stored in the database.
  512.     
  513. *************************************************/
  514. OSErr    FDBUnionEntry(TFontDbaseHdl hDbase, long entryOffset, gxFlatFontListItem *pageDbase);
  515. OSErr    FDBUnionEntry(TFontDbaseHdl hDbase, long entryOffset, gxFlatFontListItem *pageDbase)
  516.     {
  517.         long                        i, j;
  518.         register short    numLongs;
  519.         OSErr                        status = noErr;
  520.         unsigned char        *pDoc, *pPage;                        // point into stuff for doc and page.
  521.         TFDBEntry                *theEntry;                                // the entry to union pageDbase with.
  522.         long                        uniqueNameL;                            // the long alligned number of bytes in the name.
  523.         unsigned long        *docBits, *pageBits;            // the document glyph bits and the page glyph bits.
  524.         long                        glyphBitSize;                            // number of bytes in bit array.
  525.         gxFontVariation    *pageCoordinate,                    // coordinate from the page database
  526.                                         *docCoordinate;                        // coordinate from the doc database.
  527.         long                        axisCount;
  528.         
  529.         axisCount = pageDbase->axisCount;
  530.         uniqueNameL = 4 * ((pageDbase->length + 3) / 4);
  531.         glyphBitSize = 4 * ((pageDbase->glyphCount + 31) / 32);
  532.         
  533.         /** First union the main bit array **/
  534.         
  535.         pDoc = (unsigned char*)((long)(*hDbase)->fontDbaseInfo + entryOffset);                                            // point pDoc at entry.
  536.         docBits = (unsigned long*)(pDoc + sizeof(TFDBEntry) + uniqueNameL);                                                    // offset from pDoc to bits.
  537.         pageBits = (unsigned long*)( (long)pageDbase + sizeof(gxFlatFontListItem) + uniqueNameL);        // Point to page bits
  538.         
  539.         //dprintf(notrace, "font: %d, docBits: %X, pageBits: %X", pageDbase->fontID, docBits, pageBits);
  540.         
  541.         for (numLongs = glyphBitSize/4 - 1; numLongs >= 0; --numLongs)
  542.             *docBits++ |= *pageBits++;
  543.  
  544.  
  545.         /***************
  546.         
  547.             Now union all fo the bits/Variation pairs, 
  548.             add any new pairs necessary.
  549.             
  550.         ****************/
  551.  
  552.         /* point pPage at first bits/variations pair in page database */
  553.  
  554.         pPage = (unsigned char*)((long)pageDbase + sizeof(gxFlatFontListItem) + uniqueNameL + glyphBitSize);        
  555.  
  556.         /** Loop through the bit/variation pairs in the page **/
  557.         
  558.         for (i = 0; i < pageDbase->variationCount; ++i) {
  559.         
  560.             pageBits = (unsigned long*)pPage;
  561.             pageCoordinate = (gxFontVariation*)(pPage + glyphBitSize);
  562.             
  563.             pDoc = (unsigned char*)((long)(*hDbase)->fontDbaseInfo + entryOffset);
  564.             theEntry = (TFDBEntry*)(pDoc);
  565.                         
  566.             /* point at first pair in document entry */
  567.             pDoc += sizeof(TFDBEntry) + uniqueNameL + glyphBitSize;
  568.  
  569.             /* Loop through the document pairs to find match */
  570.             
  571.             for (j = 0; j < theEntry->fontInfo.variationCount; ++j) {
  572.             
  573.                 docCoordinate = (gxFontVariation*)(pDoc + glyphBitSize);
  574.                 
  575.                 if (FDBEqualVariations(axisCount, docCoordinate, pageCoordinate)) {
  576.                 
  577.                     /* If we found a match, union the bits */
  578.                     docBits = (unsigned long*)pDoc;            
  579.                     for (numLongs = glyphBitSize/4 - 1; numLongs >= 0; --numLongs)
  580.                         *docBits++ |= *pageBits++;
  581.                 
  582.                     break;
  583.                 
  584.                 }//end if
  585.                 
  586.                 /* point to next pair in doc entry */
  587.             
  588.                 pDoc += glyphBitSize + axisCount * sizeof(gxFontVariation);        
  589.                 
  590.             }//end for
  591.             
  592.             /* if we didn't get a match, add the new pair to the document entry */
  593.             if (j >= theEntry->fontInfo.variationCount) {
  594.             
  595.                 status = FDBAddVariationBitPair(hDbase, entryOffset, pageCoordinate, pageBits);
  596.                 nrequire(status, failed_AddPair);
  597.             
  598.             }//end if
  599.         
  600.             /* point to next pair in page. */
  601.             
  602.             pPage += glyphBitSize + axisCount * sizeof(gxFontVariation);
  603.         
  604.         }//end for
  605.     
  606.     
  607. failed_AddPair:
  608.  
  609.         return(status);
  610.         
  611.     }//FDBUnionEntry
  612.  
  613.  
  614. //<FF>
  615. /**********************************
  616.  
  617.         Function:    FDBSetMac8bitEncodingGlyphs
  618.         
  619.         Function takes the glyph bits from the tag
  620.         and sets them up to reflect the 8 bit Macintosh
  621.         encoding for the current system.
  622.         
  623. ***********************************/
  624. OSErr FDBSetMac8bitEncodingGlyphs(gxFlatFontListItem *pageDbase);
  625. OSErr FDBSetMac8bitEncodingGlyphs(gxFlatFontListItem *pageDbase)
  626.     {
  627.         OSErr                            status;
  628.         long                            uniqueNameLengthL;
  629.         long                            *pageBits;
  630.         unsigned short        *aGlyphCode, *theGlyphCodes;
  631.         register short        i;
  632.         Handle                        h;    
  633.         long                            length;
  634.         
  635.         uniqueNameLengthL = 4 * ((pageDbase->length + 3) / 4);
  636.         pageBits = (long*)((long)pageDbase + sizeof(gxFlatFontListItem) + uniqueNameLengthL);
  637.             
  638.         status = PrNewHandle(&h, 256 * sizeof(unsigned short));
  639.         nrequire(status, failed_alloc);
  640.         HLock(h);
  641.  
  642.         theGlyphCodes = (unsigned short*)*h;
  643.         
  644.         length = MakeMac8BitEncoding(pageDbase->fontID, theGlyphCodes);
  645.         check(length == 256);
  646.         
  647.         /** Now go and set all of the bits for the glyphs that came back **/
  648.  
  649.         aGlyphCode = theGlyphCodes;
  650.         for (i = 255; i != -1; --i) {
  651.         
  652.             if (*aGlyphCode <= pageDbase->glyphCount) {
  653.             
  654.                 BITSET(pageBits, *aGlyphCode);
  655.                 
  656.             } else {
  657.             
  658.                 #if DEBUGLEVEL > 0            
  659.                     dprintf(trace, "asked to encode glyph: %d, outside of font's range of %d", *aGlyphCode, pageDbase->glyphCount);
  660.                 #endif
  661.                 
  662.             }//end if
  663.             
  664.             ++aGlyphCode;
  665.             
  666.         }//end for
  667.         
  668.         /** Set the bits for the first snapshot also (to help apps like freehand) **/
  669.         
  670.         if (pageDbase->variationCount >= 1) {
  671.         
  672.             /* Skip to the first bit/variation combo, which is right after the main bit array */
  673.             pageBits = (long*)((unsigned char*)pageBits + 4 * ((pageDbase->glyphCount + 31) / 32));
  674.  
  675.             /* Evil code, should modularize -- Keep in sync with copy above !!!*/
  676.             aGlyphCode = theGlyphCodes;
  677.             for (i = 255; i != -1; --i) {
  678.             
  679.                 if (*aGlyphCode <= pageDbase->glyphCount) {
  680.                 
  681.                     BITSET(pageBits, *aGlyphCode);
  682.                     
  683.                 } else {
  684.                 
  685.                     #if DEBUGLEVEL > 0            
  686.                     dprintf(trace, "asked to encode glyph: %d, outside of font's range of %d", *aGlyphCode, pageDbase->glyphCount);
  687.                     #endif
  688.                     
  689.                 }//end if
  690.                 
  691.                 ++aGlyphCode;
  692.                 
  693.             }//end for
  694.         
  695.         }//end if
  696.             
  697.         DisposeHandle(h);
  698.         
  699. failed_alloc:
  700.         return(status);
  701.     
  702.     }//FDBSetMac8bitEncodingGlyphs
  703. //<FF>
  704. /**********************************
  705.         
  706.         Function: FDBAddEntry:
  707.         
  708.         Function adds a page database to the document database.
  709.         Data is stored at the end.  Handle is grown to accomodate new data.
  710.         
  711.         hDbase:                handle to the font database record.
  712.         pageFontTag:    the tag from the page.  Assumed to be locked.
  713.         useMac8bitEncoding:  bolean indicates whether or not to set flag for using 8bit encoding.        
  714. ************************************/
  715. OSErr FDBAddEntry(TFontDbaseHdl hDbase, gxFlatFontListItem *dBaseEntry, Boolean useMac8bitEncoding);
  716. OSErr FDBAddEntry(TFontDbaseHdl hDbase, gxFlatFontListItem *dBaseEntry, Boolean useMac8bitEncoding)
  717.     {
  718.         OSErr                                status;    
  719.         long                                newSize;                // new size for database handle.
  720.         long                                entrySize;            // size of unique name plus glyph bits and variation bits.                
  721.         TFontDbasePtr                pDbase;
  722.         TFDBEntry                        *newEntry;
  723.         long                                offset;
  724.         
  725.         pDbase = *hDbase;
  726.                 
  727.         /** Compute the size of the variable length portion of the flatFontListItem **/
  728.  
  729.         entrySize = FDBComputeEntrySize(dBaseEntry);
  730.                 
  731.         newSize = sizeof(TFontDbaseRec) + pDbase->nextOffset + sizeof(TFDBEntry) + entrySize;
  732.         
  733.         status = PrSetHandleSize((Handle)hDbase, newSize);
  734.         nrequire(status, failed_SetSize);
  735.  
  736.         pDbase = *hDbase;                // may have moved when setting size.
  737.         
  738.         /** Copy the current page number and the data from the tag into the database **/
  739.         
  740.         newEntry = (TFDBEntry*)((long)&(pDbase->fontDbaseInfo) + pDbase->nextOffset);
  741.         newEntry->firstPage = pDbase->currPage;
  742.         
  743.         if (useMac8bitEncoding)
  744.             newEntry->flags = fdbUseMac8Bit;
  745.         else
  746.             newEntry->flags = 0;
  747.  
  748.         memcpy( &(newEntry->fontInfo), dBaseEntry, sizeof(gxFlatFontListItem) + entrySize);
  749.         
  750.         /** Store the offset in the collection: data is offset, collection tag is font. **/
  751.         
  752.         offset = pDbase->nextOffset;
  753.         status = AddCollectionItem( pDbase->docFonts,
  754.                                                                 (CollectionTag)dBaseEntry->fontID,    // the collection tag is the font ID
  755.                                                                 nil,                                                                // id nil.
  756.                                                                 sizeof(long),                                                // data is a long.
  757.                                                                 &offset);                                                        // data.
  758.         nrequire(status, failed_AddCollection);
  759.         
  760.         /** Update the offset for writing the next entry **/
  761.         
  762.         pDbase = *hDbase;                            // may have moved when adding collection item.
  763.         
  764.         pDbase->nextOffset += sizeof(TFDBEntry) + entrySize;
  765.         ++(pDbase->numFonts);
  766.  
  767. failed_AddCollection:
  768. failed_SetSize:    
  769.         return(status);
  770.         
  771.     }//FDBAddEntry
  772.  
  773.  
  774. //<FF>
  775. /****************************************
  776.     
  777.     Function: FDBSetGlyphBits.
  778.     
  779.     Function sets the glyph bits for the glyphs passed in.
  780.     If the glyphs array is nil, all bits are set.
  781.  
  782.     bits:                        target bit array.  (Must be big enough to hold largest glyph index)
  783.     glyphBitSize:        size of bit array in bytes.
  784.     numGlyphs:            number of glyphs.
  785.     glyphs:                    array of glyph codes to set.  If nil, all bits are set.
  786.     
  787. ****************************************/
  788. void FDBSetGlyphBits(unsigned char *bits, long glyphBitSize, long numGlyphs, unsigned short glyphs[]);
  789. void FDBSetGlyphBits(unsigned char *bits, long glyphBitSize, long numGlyphs, unsigned short glyphs[])
  790.     {
  791.         unsigned short    *aGlyph;
  792.         long                        i;
  793.         long                        glyphCode;
  794.  
  795.         check(bits);
  796.                 
  797.         if (glyphs == nil) {
  798.         
  799.             memset(bits, 0xFF, glyphBitSize);
  800.             
  801.         } else {
  802.             
  803.             memset(bits, 0x00, glyphBitSize);
  804.             
  805.             aGlyph = glyphs;
  806.             for (i = 0; i < numGlyphs; ++i) {
  807.             
  808.                 glyphCode = *aGlyph++;
  809.                 
  810.                 #if DEBUGLEVEL > 0            
  811.                 if (glyphCode >= glyphBitSize * 8)
  812.                     dprintf(notrace, "Fatal error: glyph code: %d", glyphCode);
  813.                 #endif
  814.                 
  815.                 BITSET(bits, glyphCode);            
  816.             
  817.             }//end for
  818.  
  819.         }//end if
  820.  
  821.     }//FDBSetGlyphBits
  822.     
  823.  
  824.  
  825. //<FF>
  826. /*******************************************************
  827.  
  828.     Function: FontDbaseAddStyleEntry
  829.     
  830.     Function adds an entry to the database for the style and
  831.     glyphs passed in.  This is used to build entries for the default
  832.     font (for font substitution) as well as for QD shapes.
  833.     
  834.     fontDbase:            a font database object.
  835.     theStyle:                Style containing font and variations for the entry.
  836.     numGlyphs:            number of glyphs in array.
  837.     glyphs:                    array of glyphs to set bits for.  (If nil, set all bits)
  838.     use8BitMacEncoding:   use 8 bit encoding?
  839.         
  840. *********************************************************/
  841. OSErr    FontDbaseAddStyleEntry(TFontDbase fontDbase, gxStyle theStyle, long numGlyphs, unsigned short glyphs[], Boolean use8BitMacEncoding)
  842.     {
  843.         OSErr                                        status;
  844.         Handle                                    hItem;
  845.         gxFlatFontListItem            *item;
  846.         long                                        size;
  847.         long                                        glyphCount;
  848.         long                                        axisCount;
  849.         long                                        nameLength;                // length of font name.
  850.         long                                        nameLengthL;            // long alligned name length;
  851.         gxFont                                    theFont;
  852.         long                                        glyphBitSize;
  853.         unsigned char*                    bits;                            // I know, generally a long but this makes ptr math easier.
  854.         gxFontVariation                    *variations;
  855.         gxFontName                            name;
  856.         gxFontPlatform                    platform;
  857.         gxFontScript                        script;
  858.         gxFontLanguage                    language;
  859.         long                                        nameIndex;
  860.                 
  861.         theFont = GXGetStyleFont(theStyle);
  862.         
  863.         glyphCount = GXCountFontGlyphs(theFont);
  864.         axisCount = GXCountFontVariations(theFont);
  865.         glyphBitSize = 4 * ((glyphCount + 31) / 32);
  866.  
  867.         /* figure out the size of the item */
  868.         
  869.         size = sizeof(gxFlatFontListItem)  + glyphBitSize;
  870.         
  871.         /* if it is a variation font, make room for a variation/bit pair */
  872.         if (axisCount > 0)
  873.             size += glyphBitSize + axisCount * sizeof(gxFontVariation);
  874.             
  875.         /* Add in space for the name (Unique name, if none use PostScript name */
  876.         nameLength = GXFindFontName(theFont, gxUniqueFontName, gxNoPlatform, gxNoScript, gxNoLanguage, nil, &nameIndex);
  877.         if (nameLength == 0)
  878.             nameLength = GXFindFontName(theFont, gxPostscriptFontName, gxNoPlatform, gxNoScript, gxNoLanguage, nil, &nameIndex);
  879.         nameLengthL = 4 * (( nameLength + 3) / 4);
  880.         
  881.         size += nameLengthL;
  882.                     
  883.         /* Get memory for the item */
  884.         
  885.         status = PrNewHandle(&hItem, size);
  886.         nrequire(status, failed_alloc);
  887.         HLock(hItem);
  888.         item = (gxFlatFontListItem*)(*hItem);
  889.  
  890.         /* Now fill in the primary fields of the item */
  891.         
  892.         item->fontID = theFont;
  893.         
  894.         /*** Fill in the unique name field ***/
  895.         
  896.         item->length = nameLength;
  897.         GXGetFontName(theFont, nameIndex, &name, &platform, &script, &language,
  898.                                         (unsigned char*)(item) + sizeof(gxFlatFontListItem));
  899.         
  900.         item->name = name; item->script = script; item->language = language; item->platform = platform;
  901.         
  902.         check(name == gxUniqueFontName);
  903.         
  904.         /* fill in the variation/glyph information */
  905.         item->glyphCount = glyphCount;
  906.         item->axisCount = axisCount;
  907.         if (axisCount)
  908.             item->variationCount = 1;                    // allow for one (default) variation/bit pair.
  909.         else
  910.             item->variationCount = 0;
  911.         
  912.         /* Fill in the primary glyph bits */
  913.         bits = (unsigned char*)item + sizeof(gxFlatFontListItem) + nameLengthL; 
  914.         FDBSetGlyphBits(bits, glyphBitSize, numGlyphs, glyphs);
  915.         
  916.         /* Fill in variation/bit pair if necessary */
  917.         if (axisCount > 0) {
  918.                     
  919.             /* Point to the first bit array in the pairs. (its right after main bits) */
  920.             bits += glyphBitSize; 
  921.             FDBSetGlyphBits(bits, glyphBitSize, numGlyphs, glyphs);
  922.             
  923.             /* point to variations */
  924.             variations = (gxFontVariation*)(bits + glyphBitSize);
  925.             
  926.             /* Fill in the variations */
  927.             
  928.             GXSetStyleFont(theStyle, theFont);
  929.             GXGetStyleFontVariationSuite(theStyle, variations);
  930.  
  931.         }//end if
  932.         
  933.         /** Now add the item to the database **/
  934.         
  935.         status = FontDbaseAddItem(fontDbase, item, use8BitMacEncoding);
  936.         ncheck(status);
  937.  
  938.         DisposeHandle(hItem);
  939.  
  940.         
  941. failed_alloc:
  942.         return(status);
  943.     
  944.     }//_FontDbaseAddStyleEntry
  945.  
  946.  
  947.  
  948.  
  949. //<FF>
  950. /*******************************************************
  951.  
  952.     Function: FDBAddDefaultFontEntry
  953.     
  954.     Function adds an entry to the database for the GX default
  955.     font.  The entry will have all of the glyph bits set.
  956.     This is used so font substitution works.
  957.     
  958.     All of the bits are set because we don't know in advance
  959.     what glyphs will be used.
  960.     
  961. *********************************************************/
  962. OSErr    FDBAddDefaultFontEntry(TFontDbaseHdl hDbase, Boolean use8BitMacEncoding);
  963. OSErr    FDBAddDefaultFontEntry(TFontDbaseHdl hDbase, Boolean use8BitMacEncoding)
  964.     {
  965.         OSErr            status;
  966.         gxStyle        theStyle;
  967.                 
  968.     
  969.         /* Get the default style, give it default font */
  970.         
  971.         theStyle = GXNewStyle();
  972.         GXSetStyleFont(theStyle, GXGetDefaultFont());
  973.         
  974.         status = FontDbaseAddStyleEntry((TFontDbase)hDbase, theStyle, 0, nil, use8BitMacEncoding);
  975.         ncheck(status);
  976.  
  977.         GXDisposeStyle(theStyle);
  978.         
  979.         return(status);
  980.         
  981.     }//FDBAddDefaultFontEntry
  982.  
  983. //<FF>
  984. /*******************************************************
  985.  
  986.     Function:        FDBBuildOffsetCollection
  987.     
  988.     Function builds the collections that map from font ID's 
  989.     to offsets into the database.  This is done by finding the
  990.     font ID that corresponds to the name stored in the database.
  991.  
  992.  
  993.     It is assumed that there is no collection in the font database
  994.     record.  The handle should contain a valid numFonts and fontDbaseInfo.
  995.     
  996. ********************************************************/
  997.  
  998. OSErr FDBBuildOffsetCollection(TFontDbaseHdl hDbase);
  999. OSErr FDBBuildOffsetCollection(TFontDbaseHdl hDbase)
  1000.     {
  1001.         OSErr                            status = noErr;    
  1002.         long                            i;
  1003.         TFontDbasePtr            pDbase;
  1004.         gxFont                        fontID;                            // the font reference.
  1005.         unsigned char            *fontName;                    // Name of the current font.
  1006.         TFDBEntry                    *dBaseEntry;                // An entry in the database.
  1007.         long                            offset;                            // offset into data for an entry.
  1008.         Boolean                        fontSubstitution;        // Do we need font substitution?
  1009.         long                            fontCount;                    // Number of legal (non-substituted fonts) in database.
  1010.         Boolean                        useMac8BitEncoding;    // Use 8 bit encoding for default font.
  1011.         
  1012.         useMac8BitEncoding = false;
  1013.         HLock((Handle)hDbase);
  1014.         pDbase = *hDbase;
  1015.         
  1016.         fontSubstitution = false;                        // initialize to no substitution necessary.
  1017.         
  1018.         /** Allocate the collection **/
  1019.         
  1020.         require_action(pDbase->docFonts = NewCollection(), failed_Collection, status = MemError(););
  1021.         
  1022.         /************************
  1023.             Now loop through the data to find id's corresponding to the fonts
  1024.             and store the offsets into the database in the collection
  1025.         *************************/
  1026.         offset = 0;
  1027.         fontCount = 0;
  1028.         for (i = 0; i < pDbase->numFonts; ++i) {
  1029.                         
  1030.             dBaseEntry = (TFDBEntry*)((long)&(pDbase->fontDbaseInfo) + offset);
  1031.             
  1032.             fontName = (unsigned char*)((long)&(dBaseEntry->fontInfo) + sizeof(gxFlatFontListItem));     // The name is first field at end of record.
  1033.  
  1034.             
  1035.             /** Find the font id corresponding to the name, if it's not there, turn on substitution **/
  1036.                                         
  1037.             if (GXFindFonts(0,     
  1038.                         dBaseEntry->fontInfo.name,
  1039.                         dBaseEntry->fontInfo.platform,
  1040.                         dBaseEntry->fontInfo.script,
  1041.                         dBaseEntry->fontInfo.language,
  1042.                         dBaseEntry->fontInfo.length,    &fontName[0], 1, 1, &fontID) == 0) {
  1043.                         
  1044.                 fontSubstitution = true;            // turn on font substitution.
  1045.                 if (dBaseEntry->flags & fdbUseMac8Bit)
  1046.                     useMac8BitEncoding = true;
  1047.  
  1048.                 #if DEBUGLEVEL >= DEBUGFEEDBACK            
  1049.                 dprintf(trace, "Font Substitution For: %s", fontName);
  1050.                 #endif
  1051.                 
  1052.             } else {
  1053.  
  1054.                 /*** Add the font to the collection **/
  1055.  
  1056.                 status = AddCollectionItem( pDbase->docFonts,
  1057.                                                                         (CollectionTag)fontID,        // the collection tag is the font ID
  1058.                                                                         nil,                                            // id nil
  1059.                                                                         sizeof(long),                            // the data is the offset, a long.
  1060.                                                                         &offset);
  1061.                 nrequire(status, failed_AddCollection);
  1062.                 
  1063.                 fontCount += 1;                    // this will be the number we successfuly found.
  1064.                 
  1065.             }//end if
  1066.             
  1067.             dBaseEntry->fontInfo.fontID = fontID;
  1068.             
  1069.             /** Add the size of the entry to the current offset **/
  1070.             
  1071.             offset += sizeof(TFDBEntry) + FDBComputeEntrySize(&(dBaseEntry->fontInfo));
  1072.                                             
  1073.         }//end for
  1074.         
  1075.         pDbase->nextOffset = offset;
  1076.         pDbase->numFonts = CountCollectionItems(pDbase->docFonts);                // reset the number of fonts to match collection
  1077.  
  1078.         #if DEBUGLEVEL > 0
  1079.         if (fontCount != pDbase->numFonts)
  1080.             dprintf(notrace, "Warning, you have more than 1 font with same unique name - performance may suffer");
  1081.         #endif
  1082.             
  1083. failed_AddDefault:
  1084. failed_AddCollection:
  1085. failed_Collection:
  1086.  
  1087.         HUnlock((Handle)hDbase);
  1088.         
  1089.         
  1090.         /*******
  1091.             If there was no error but we need font substitution,
  1092.                 add a database entry for the default font.
  1093.                 This will ensure that clients know the document
  1094.                 uses whatever font the default is
  1095.         ********/
  1096.         if ( (status == noErr) && fontSubstitution) {
  1097.         
  1098.             status = FDBAddDefaultFontEntry(hDbase, useMac8BitEncoding);
  1099.             ncheck(status);
  1100.             
  1101.         }//end if
  1102.                 
  1103.         return(status);
  1104.     
  1105.     }//FDBBuildOffsetCollection
  1106.     
  1107. //<FF>
  1108. /*************************************
  1109.  
  1110.     Function: FDBReadSpoolFileFonts
  1111.     
  1112.     Function reads in fonts from spool file.
  1113.     Unfortunately, there is no good way for this to
  1114.     work through messaging.  If there ever is, we'll 
  1115.     fix it.
  1116.     
  1117. **************************************/
  1118. OSErr FDBReadSpoolFileFonts(TFontDbaseHdl hDbase);
  1119. OSErr FDBReadSpoolFileFonts(TFontDbaseHdl hDbase)
  1120.     {
  1121.         OSErr                status = noErr;
  1122.         Handle            hFileFonts;                        // handle full of font references from file.    
  1123.         Handle            sfnt;                                    // An sfnt resource.
  1124.         long                count, numLoaded;
  1125.         long                i;
  1126.         gxFont            *aFont;    
  1127.     char                 resLoadState = *(char*)0xa5e;            /* stolen from graphics toolbox library.c */
  1128.     
  1129.         count = Count1Resources('sfnt');            // find out how many.
  1130.         
  1131.         if (count == 0) {
  1132.             
  1133.             (*hDbase)->numFileFonts = 0;
  1134.             (*hDbase)->hFileFonts = nil;
  1135.             return(noErr);
  1136.             
  1137.         }//end if
  1138.         
  1139.         /** Allocate a handle for the font list **/
  1140.         
  1141.         status = PrNewHandle(&hFileFonts, count * sizeof(gxFont));
  1142.         nrequire(status, failed_alloc);
  1143.         
  1144.         SetResLoad(false);
  1145.         HLock(hFileFonts);
  1146.         aFont = (gxFont*)*hFileFonts;
  1147.         numLoaded = 0;        
  1148.         for (i = 1; i <= count; ++i) {
  1149.         
  1150.             sfnt = Get1IndResource('sfnt', i);
  1151.             require(sfnt, failed_font);
  1152.             
  1153.             *aFont++ = GXNewFont(gxResourceFontStorage, sfnt, 0);
  1154.             status = GXGetGraphicsError(nil);
  1155.             nrequire_action(status, failed_newFont, ReleaseResource(sfnt););
  1156.  
  1157.             numLoaded += 1;                // In case we have to clean up.
  1158.             
  1159.         }//end for
  1160.         
  1161.         HUnlock(hFileFonts);
  1162.         SetResLoad(resLoadState);
  1163.         
  1164.         
  1165.         (*hDbase)->numFileFonts = count;
  1166.         (*hDbase)->hFileFonts = hFileFonts;
  1167.         
  1168.         return(noErr);
  1169.         
  1170. /****** exception handling ********/
  1171.  
  1172. failed_newFont:
  1173. failed_font:
  1174.  
  1175.         status = MemError();                // find out why we failed to load the font resource.
  1176.         if (status == noErr);
  1177.             status = ResError();
  1178.         
  1179.         ncheck(status);
  1180.         
  1181.         
  1182.         /* Get rid of any fonts that were loaded */
  1183.         aFont = (gxFont*)*hFileFonts;
  1184.         for (i = 1; i <= numLoaded; ++i);
  1185.             GXDisposeFont(*aFont++);
  1186.  
  1187.         DisposeHandle(hFileFonts);
  1188.  
  1189. failed_alloc:    
  1190.  
  1191.         SetResLoad(resLoadState);
  1192.         return(status);
  1193.         
  1194.     }//FDBReadSpoolFileFonts
  1195.  
  1196.  
  1197. //<FF>
  1198. /*************************************
  1199.  
  1200.     Function: FDBNewEmptyDatabase
  1201.     
  1202.     Function creates a new and empty font database object.
  1203.     
  1204. **************************************/
  1205. OSErr FDBNewEmptyDatabase(TFontDbase *fontDbase);
  1206. OSErr FDBNewEmptyDatabase(TFontDbase *fontDbase)
  1207.     {
  1208.         OSErr                            status;
  1209.         TFontDbaseHdl            hDbase;
  1210.  
  1211.         *fontDbase = nil;
  1212.             
  1213.         status = PrNewHandleClear((Handle*)&hDbase, sizeof(TFontDbaseRec));
  1214.         nrequire(status, failed_Alloc);
  1215.  
  1216.         /********
  1217.             From NewHandleClear:
  1218.                 hFilefonts is nil,
  1219.                 numFileFonts is 0,
  1220.                 page count is 0,
  1221.                 nextOffset is 0,
  1222.                 numFonts is 0,
  1223.                 currPage is 0,
  1224.                 lockCount is 0
  1225.                 prerequisites is nil.
  1226.         *********/
  1227.  
  1228.         (*hDbase)->dbaseVersion = fdbThisVersion;    
  1229.  
  1230.         /** Allocate the collection for the database **/
  1231.  
  1232.         (*hDbase)->docFonts = NewCollection();
  1233.         require_action((*hDbase)->docFonts, failed_Collection, status = MemError(););
  1234.  
  1235.         *fontDbase = (TFontDbase)hDbase;
  1236.         
  1237. failed_Collection:
  1238. failed_Alloc:
  1239.         return(status);
  1240.         
  1241.     }//FDBNewEmptyDatabase
  1242.  
  1243.  
  1244.  
  1245. //<FF>
  1246. /*************************************
  1247.  
  1248.     Function:    FontDbaseInit
  1249.     
  1250.         Function initializes the font database
  1251.  
  1252.             fontDbase:        Handle allocated by this function containing the
  1253.                                         database.
  1254.                                         
  1255.             theFile:            A spool file to read the font database from.  If Nil is passed
  1256.                                         an empty font database is created.  Pass Nil for creating the database
  1257.                                         Pass a file to read one in.
  1258.             
  1259.             useMessages:    true to use messages to despool resource, false to call file handler directly.
  1260.  
  1261. **************************************/
  1262. OSErr FontDbaseInit(TFontDbase *fontDbase, gxSpoolFile* theFile)
  1263.     {
  1264.         OSErr                                status;
  1265.  
  1266.         if (theFile == nil) {
  1267.         
  1268.             status = FDBNewEmptyDatabase(fontDbase);
  1269.             nrequire(status, failed_Alloc);
  1270.         
  1271.         } else {
  1272.                     
  1273.             /** Read the font database in from the spool file **/
  1274.             
  1275.             // Important change.  Old GX code used messages to access the spool file.  We use the spool file C++ class here.            
  1276.             status = theFile->DespoolResource(kFontDbaseResType, printingBaseID, (Handle*)fontDbase);
  1277.             
  1278.             if (status == resNotFound) {
  1279.         
  1280.                 /** If we could not read the resouce, just create an empty database **/
  1281.  
  1282.                 #if DEBUGLEVEL > 1
  1283.                 dprintf(trace, "Couldn't load font database resource, creating empty database");
  1284.                 #endif
  1285.                 
  1286.                 status = FDBNewEmptyDatabase(fontDbase);
  1287.                 nrequire(status, failed_Alloc1);
  1288.             
  1289.             } else {
  1290.  
  1291.                 nrequire(status, failed_GetResource);
  1292.                 
  1293.                 HNoPurge((Handle)*fontDbase);                                                // better not go away!
  1294.                 DetachResource((Handle)*fontDbase);                                    // Make it a regular handle.
  1295.  
  1296.                 /** If we ever change it from a shipping version, put code in to read old versions **/
  1297.     
  1298.                 if ( (*(TFontDbaseHdl)*fontDbase)->dbaseVersion != fdbThisVersion)     {
  1299.     
  1300.                     #if DEBUGLEVEL > 1
  1301.                         dprintf(notrace, "Database version is invalid: %X", (*(TFontDbaseHdl)*fontDbase)->dbaseVersion);
  1302.                     #endif
  1303.                     status = -999;
  1304.                     goto failed_version;
  1305.     
  1306.                 }//endif
  1307.                 
  1308.             }//end if
  1309.  
  1310.             /** Read in any fonts from the spool file **/
  1311.             
  1312.             status = FDBReadSpoolFileFonts((TFontDbaseHdl)*fontDbase);
  1313.             nrequire(status, failed_readFonts);
  1314.                         
  1315.             /** Build the collection that Maps font ID's to offsets into handle **/
  1316.             
  1317.             status = FDBBuildOffsetCollection((TFontDbaseHdl)*fontDbase);
  1318.             ncheck(status);
  1319.             
  1320.             (*(TFontDbaseHdl)*fontDbase)->lockCount = 0;
  1321.             (*(TFontDbaseHdl)*fontDbase)->prerequisites = nil;
  1322.                                 
  1323.         }//end if
  1324.  
  1325. failed_version:
  1326. failed_readFonts:
  1327.  
  1328.         /** If there was an error after getting the handle, dispose of the handle before returning error **/
  1329.         if (status != noErr)
  1330.             DisposeHandle(*(Handle*)fontDbase);
  1331.  
  1332. failed_Alloc1:
  1333. failed_GetResource:
  1334. failed_Collection:
  1335. failed_Alloc:
  1336.         return(status);
  1337.  
  1338.     }//FontDbaseInit
  1339.  
  1340.  
  1341.  
  1342. //<FF>
  1343. /*************************************
  1344.  
  1345.     Function:    FontDbaseShutdown
  1346.     
  1347.         Function deallocates the font database
  1348.         or writes it to a resource in the spool file
  1349.         if specified.  
  1350.         If one is specified and the write fails
  1351.         then the handle is deallocated.
  1352.  
  1353.             fontDbase:        The font database.
  1354.             theFile:            Spool file to write database to. If Nil, database is not written.
  1355.  
  1356. **************************************/
  1357.  
  1358. OSErr FontDbaseShutdown(TFontDbase fontDbase, gxSpoolFile* theFile)
  1359.     {
  1360.         OSErr                                status = noErr;
  1361.         TFontDbasePtr                pDbase;
  1362.         gxFont                            *aFont;
  1363.         Handle                            hFileFonts;
  1364.         long                                i;
  1365.  
  1366.         #ifdef test_FontDbaseUnion
  1367.             {
  1368.                 TFontDbase            target;
  1369.                 status = _FontDbaseInit(&target, nil, false);
  1370.                 ncheck(status);
  1371.                 status = _FontDbaseUnion(fontDbase, target);
  1372.                 ncheck(status);
  1373.                 //dprintf(notrace, "source: %X, target: %X", *(TFontDbaseHdl)fontDbase, *(TFontDbaseHdl)target);
  1374.                 if (theFile != nil)
  1375.                     status = Send_GXSpoolResource(theFile, (Handle)target, kFontDbaseResType, 0);
  1376.                 ncheck(status);
  1377.             }
  1378.         #endif
  1379.         
  1380.         /* Dispose of any fonts loaded in with this database */
  1381.         
  1382.         pDbase = *(TFontDbaseHdl)fontDbase;
  1383.         hFileFonts = pDbase->hFileFonts;
  1384.         
  1385.         if (hFileFonts != nil) {
  1386.         
  1387.             HLock(hFileFonts);
  1388.             aFont = (gxFont*)*hFileFonts;
  1389.             for (i = 0; i < pDbase->numFileFonts; ++i)
  1390.                 GXDisposeFont(*aFont++);
  1391.             
  1392.             DisposeHandle(hFileFonts);
  1393.                 
  1394.         }//end if
  1395.         
  1396.     
  1397.         /* Dispose of the offset collection */
  1398.         
  1399.         pDbase = *(TFontDbaseHdl)fontDbase;
  1400.         if (pDbase->docFonts != nil)
  1401.             DisposeCollection(pDbase->docFonts);
  1402.  
  1403.  
  1404.         /* Dispose of the prerequisite collection */
  1405.         
  1406.         pDbase = *(TFontDbaseHdl)fontDbase;
  1407.         if (pDbase->prerequisites != nil)
  1408.             DisposeCollection(pDbase->prerequisites);
  1409.  
  1410.         /** Write it out if to the resource of the spool file if specified **/
  1411.         
  1412.         if (theFile != nil) {
  1413.  
  1414.             // Important change:  DL 7/26/97  Changing from using GX spool file messages to using spool file C++ class
  1415.             status = theFile->SpoolResource((Handle)fontDbase, kFontDbaseResType, printingBaseID);            
  1416.             ncheck(status);
  1417.         
  1418.         }//end if
  1419.         
  1420.         /******
  1421.             Dispose of the handle if we failed to spool it as a resource
  1422.             or a spool file was not specified
  1423.         *****/
  1424.         
  1425.         if ( (theFile == nil) || (status != noErr)) {
  1426.         
  1427.             DisposeHandle((Handle)fontDbase);
  1428.         
  1429.         }//end if
  1430.         
  1431.         return(status);
  1432.     
  1433.     }//FontDbaseShutdown
  1434.  
  1435.  
  1436.  
  1437. //<FF>
  1438. /***************************************************
  1439.         FontDbaseSetFontFlags
  1440.         
  1441.         Set the flags for a particular font in the database.
  1442.         
  1443. ****************************************************/
  1444. OSErr FontDbaseSetFontFlags(TFontDbase fontDbase, gxFont fontID, TfdbInfoFlags flags)
  1445.     {
  1446.         OSErr                    status;
  1447.         long                    entryOffset;                    // Offset into handle.
  1448.         register             unsigned char *p;
  1449.         register            TFDBEntry *entry;
  1450.         
  1451.         status = GetCollectionItem((*(TFontDbaseHdl)fontDbase)->docFonts, 
  1452.                                                             (CollectionTag)fontID,                                        // tag is the font id.
  1453.                                                             nil,
  1454.                                                             nil,
  1455.                                                             &entryOffset);
  1456.         nrequire(status, failed_GetItem);
  1457.         
  1458.         p = (unsigned char*)((*(TFontDbaseHdl)fontDbase)->fontDbaseInfo) + entryOffset;     // Point to entry.
  1459.         entry = (TFDBEntry*)(p);
  1460.         entry->flags = flags;
  1461.         
  1462. failed_GetItem:        
  1463.         return(status);
  1464.     
  1465.     }//FontDbaseSetFontFlags
  1466.  
  1467.  
  1468. //<FF>
  1469. /*************************************
  1470.  
  1471.     Function:    FontDbaseAddItem
  1472.     
  1473.     Function unions a single flatFontListItem
  1474.     with the document font database.
  1475.     
  1476. **************************************/
  1477. OSErr    FontDbaseAddItem(TFontDbase fontDbase, gxFlatFontListItem *item, Boolean useMac8bitEncoding)
  1478.     {
  1479.         OSErr                            status;
  1480.         long                            entryOffset;        // offset into database.
  1481.     
  1482.             
  1483.         /** If we are told to just use the mac 8 bit encoding, set the glyph bits **/
  1484.  
  1485.         if (useMac8bitEncoding) {
  1486.             
  1487.             status = FDBSetMac8bitEncodingGlyphs(item);
  1488.             nrequire(status, failed_8bit);
  1489.             
  1490.         }//end if
  1491.  
  1492.         /*****
  1493.  
  1494.             Get the entry out of the database for the current font or add it
  1495.             if it does not exist
  1496.  
  1497.         ******/
  1498.         
  1499. #if DEBUGLEVEL > 0
  1500.         
  1501.         /** To avoid annoying collection manager assertion in debugging version **/
  1502.         
  1503.         if (CollectionTagExists((*(TFontDbaseHdl)fontDbase)->docFonts, (CollectionTag)item->fontID) )
  1504.             status = GetCollectionItem((*(TFontDbaseHdl)fontDbase)->docFonts, 
  1505.                                                                     (CollectionTag)item->fontID,        // tag is the font id.
  1506.                                                                     nil,
  1507.                                                                     nil,
  1508.                                                                     &entryOffset);
  1509.         else
  1510.             status = collectionItemNotFoundErr;
  1511. #else
  1512.             status = GetCollectionItem((*(TFontDbaseHdl)fontDbase)->docFonts, 
  1513.                                                                     (CollectionTag)item->fontID,        // tag is the font id.
  1514.                                                                     nil,
  1515.                                                                     nil,
  1516.                                                                     &entryOffset);
  1517. #endif
  1518.  
  1519.         if ( (status == collectionItemNotFoundErr) || (status == collectionIndexRangeErr)) {
  1520.         
  1521.             /** If the item was not found, add a new entry to the database **/    
  1522.             
  1523.             status = FDBAddEntry((TFontDbaseHdl)fontDbase, item, useMac8bitEncoding);
  1524.             nrequire(status, failed_AddEntry);
  1525.         
  1526.         } else if (status == noErr) {
  1527.         
  1528.             /** If an entry existed for this font, union the current item with the one we already have **/
  1529.         
  1530.             status = FDBUnionEntry((TFontDbaseHdl)fontDbase, entryOffset, item);
  1531.             nrequire(status, failed_Union);
  1532.         
  1533.         }//end if
  1534.  
  1535. failed_Union:
  1536. failed_AddEntry:
  1537. failed_Collection:
  1538. failed_8bit:
  1539.  
  1540.         return(status);
  1541.         
  1542.     }//FontDbaseAddItem
  1543.  
  1544.  
  1545. //<FF>
  1546. /*************************************
  1547.  
  1548.     Function:    FontDbaseAddPage
  1549.     
  1550.     Function unions in the database from a shape into
  1551.     the document font database
  1552.     
  1553.         fontDbase:                            A valid document font database handle.
  1554.  
  1555.         thePage:                                the shape containing the page after it has been flattened
  1556.                                                                 so it has a valid font database tag.
  1557.                                                                 
  1558.         useMac8bitEncoding:            true if you want to add all of the glyphs for the standard mac encoding
  1559.                                                                 rather than the glyphs that are in the document that are set.
  1560.         
  1561. **************************************/
  1562.         
  1563. OSErr    FontDbaseAddPage( TFontDbase fontDbase, gxShape thePage, Boolean useMac8bitEncoding)
  1564.     {
  1565.         OSErr                                status = noErr;
  1566.         long                                i;
  1567.         long                                nFonts;                    // number of fonts used on the page.
  1568.         gxTag                                dBaseTag;                // font database tag.
  1569.         gxFlatFontListItem    *pageDbase;            // Entry for a font from the page.
  1570.  
  1571.         ++((*(TFontDbaseHdl)fontDbase)->currPage);                // Increment the current page.
  1572.  
  1573.         nFonts = GXGetShapeTags(thePage, gxFlatFontListItemTag, 1, gxSelectToEnd, nil);
  1574.         
  1575.         for (i = 1; (i <= nFonts) && (status == noErr); ++i) {
  1576.         
  1577.         
  1578.             /** Get the tag data for a font in the page **/
  1579.             
  1580.             GXGetShapeTags(thePage, gxFlatFontListItemTag, i, 1, &dBaseTag);
  1581.             GXLockTag(dBaseTag);
  1582.             nrequire(status = GXGetGraphicsError(nil), failed_GetAndLockTag);
  1583.  
  1584.             pageDbase = (gxFlatFontListItem*)GXGetTagStructure(dBaseTag, nil);
  1585.             
  1586.             status = FontDbaseAddItem(fontDbase, pageDbase, useMac8bitEncoding);
  1587.             nrequire(status, failed_AddItem);
  1588.                 
  1589. failed_AddItem:
  1590.  
  1591.             GXUnlockTag(dBaseTag);
  1592.         
  1593.         }//end for
  1594.         
  1595. failed_GetAndLockTag:
  1596.  
  1597.         return(status);
  1598.  
  1599.     }//FontDbaseAddPage
  1600.  
  1601.  
  1602.  
  1603. //<FF>
  1604. /****************************************
  1605.  
  1606.     Function: FontDbaseGetFontInfo
  1607.     
  1608.     Function returns information about the font database
  1609.     entry.  (Yes some of this could simply be obtained through
  1610.     standard gx font api, but this is a shortcut.
  1611.     
  1612.     fontDbase:                    The font database.
  1613.     fontID:                            The font to get info for.
  1614.     glyphCount:                    <-- Number of glyphs in font.
  1615.     axisCount:                    <-- Number of variation axes in font.
  1616.     variationCount:            <-- Number of variation/bit pairs in database for the font.
  1617.     flags:                            <-- font database flags for this font.
  1618.     
  1619. *******************************************/
  1620. OSErr FontDbaseGetFontInfo(TFontDbase fontDbase, gxFont fontID, long *glyphCount, long *axisCount, long *variationCount, TfdbInfoFlags *flags)
  1621.     {
  1622.     
  1623.         OSErr                    status;
  1624.         long                    entryOffset;                    // Offset into handle.
  1625.         register             unsigned char *p;
  1626.         register            TFDBEntry *entry;
  1627.         
  1628.         status = GetCollectionItem((*(TFontDbaseHdl)fontDbase)->docFonts, 
  1629.                                                             (CollectionTag)fontID,                                    // tag is the font id.
  1630.                                                             nil,
  1631.                                                             nil,
  1632.                                                             &entryOffset);
  1633.         nrequire(status, failed_GetItem);
  1634.         
  1635.         p = (unsigned char*)((*(TFontDbaseHdl)fontDbase)->fontDbaseInfo) + entryOffset;     // Point to entry.
  1636.                 
  1637.         entry = (TFDBEntry*)(p);
  1638.         
  1639.         if (flags != nil)
  1640.             *flags = entry->flags;
  1641.     
  1642.         if (glyphCount != nil)    
  1643.             *glyphCount = entry->fontInfo.glyphCount;    
  1644.             
  1645.         if (axisCount != nil)
  1646.             *axisCount = entry->fontInfo.axisCount;
  1647.             
  1648.         if (variationCount != nil)
  1649.             *variationCount = entry->fontInfo.variationCount;            
  1650.             
  1651. failed_GetItem:
  1652.  
  1653.         return(status);    
  1654.     
  1655.     }//FontDbaseGetFontInfo
  1656.  
  1657.  
  1658. //<FF>
  1659. /****************************************
  1660.  
  1661.     Function:        FontDbaseGetGlyphBits
  1662.     
  1663.     Function returns a pointer to the bit 
  1664.     array of glyph usage for a particular font.
  1665.     The pointer is only guarenteed to be valid
  1666.     if the font database is first locked in memory.
  1667.     However, the font database is not assumed
  1668.     to be locked before this call.
  1669.     
  1670.     fontDbase:            The font database.
  1671.     fontID:                    The font to get bits of.
  1672.     snapshot:                The index of the variation snapshot to retrieve bits for.  (0 means union of all bits)
  1673.     glyphBits:            <-- Pointer returned to bit array.
  1674.     variations:            <-- Pointer to returned variation coordinate.
  1675.     
  1676. ******************************************/
  1677. OSErr    FontDbaseGetGlyphBits(TFontDbase fontDbase, gxFont fontID, long snapshot, unsigned long* *glyphBits, gxFontVariation* *variations)
  1678.     {
  1679.         OSErr                    status;
  1680.         long                    entryOffset;                    // Offset into handle.
  1681.         register             unsigned char *p;
  1682.         register            TFDBEntry *entry;
  1683.         long                    glyphBitSize;
  1684.         
  1685.         status = GetCollectionItem((*(TFontDbaseHdl)fontDbase)->docFonts, 
  1686.                                                             (CollectionTag)fontID,                                    // tag is the font id.
  1687.                                                             nil,
  1688.                                                             nil,
  1689.                                                             &entryOffset);
  1690.         nrequire(status, failed_GetItem);
  1691.         
  1692.         p = (unsigned char*)((*(TFontDbaseHdl)fontDbase)->fontDbaseInfo) + entryOffset;     // Point to entry.
  1693.                     
  1694.         entry = (TFDBEntry*)p;
  1695.                         
  1696.         p += sizeof(TFDBEntry) + 4 * ((entry->fontInfo.length + 3) / 4);                // Skip name.
  1697.  
  1698.         /* p is now pointing at main bit array */
  1699.         
  1700.         if (snapshot > 0) {
  1701.         
  1702.             /* Skip to the right bit/variation pair */
  1703.  
  1704.             glyphBitSize = 4 * ((entry->fontInfo.glyphCount + 31) / 32);
  1705.             
  1706.             p += glyphBitSize;            // Skip past main bit array.
  1707.             
  1708.             p += (snapshot - 1) * (glyphBitSize + entry->fontInfo.axisCount * sizeof(gxFontVariation));
  1709.         
  1710.         }//end if
  1711.  
  1712.         if (glyphBits != nil)
  1713.             *glyphBits = (unsigned long*)p;
  1714.             
  1715.         if (variations != nil)
  1716.             *variations = (gxFontVariation*)(p + glyphBitSize);
  1717.             
  1718.             
  1719.         //dprintf(notrace, "font: %d, nGlyphs: %d, bits: %X", fontID, entry->fontInfo.glyphCount, p);
  1720.  
  1721. failed_GetItem:
  1722.  
  1723.         return(status);    
  1724.     
  1725.     }//FontDbaseGetGlyphBits
  1726.  
  1727. //<FF>
  1728. /****************************************
  1729.  
  1730.     Function:        FontDbaseGetIndexedFont
  1731.     
  1732.     Function gets a font reference from the
  1733.     database by index. Index is 1 based.
  1734.     
  1735.     fontDbase:            A valid font database.
  1736.     index:                    The index of the font to get (1 based)
  1737.     fontID:                    (returned)  The id of the font.
  1738.     
  1739. *****************************************/
  1740. OSErr    FontDbaseGetIndexedFont(TFontDbase fontDbase, long index, gxFont *fontID)
  1741.     {
  1742.         OSErr                    status;
  1743.     
  1744.         status = GetIndexedCollectionItemInfo((*(TFontDbaseHdl)fontDbase)->docFonts, index, 
  1745.                                                                                          (CollectionTag*)fontID, nil, nil, nil);
  1746.         ncheck(status);
  1747.  
  1748.         return(status);
  1749.     
  1750.     }//FontDbaseGetIndexedFont
  1751.  
  1752.  
  1753.  
  1754. /****************************************
  1755.  
  1756.     Function:        FontDbaseCountFonts
  1757.     
  1758.     Function returns the number of fonts for the document
  1759.     
  1760. *****************************************/
  1761. OSErr    FontDbaseCountFonts(TFontDbase fontDbase, long *numFonts)
  1762.     {
  1763.     
  1764.         *numFonts = (*(TFontDbaseHdl)fontDbase)->numFonts;
  1765.         
  1766.         return(noErr);
  1767.         
  1768.     }//FontDbaseCountFonts
  1769.     
  1770.  
  1771.  
  1772. /******************************************
  1773.  
  1774.     Function:        FontDbaseLock
  1775.     
  1776.     Locks down the font database in memory so 
  1777.     pointers into it stay valid (such as glyphBits)
  1778.     
  1779. ********************************************/
  1780. OSErr    FontDbaseLock(TFontDbase fontDbase)
  1781.     {
  1782.         register TFontDbasePtr pDbase = *(TFontDbaseHdl)fontDbase;
  1783.         
  1784.         if (pDbase->lockCount == 0)
  1785.             HLock((Handle)fontDbase);
  1786.         
  1787.         
  1788.         pDbase->lockCount += 1;
  1789.         
  1790.         return(MemError());
  1791.     }
  1792.  
  1793.  
  1794.  
  1795. /*******************************************
  1796.  
  1797.     Function:  FontDbaseUnlock
  1798.     
  1799.     Unlocks the font database in memory.
  1800.     
  1801. ********************************************/
  1802. OSErr    FontDbaseUnlock(TFontDbase fontDbase)
  1803.     {
  1804.         register TFontDbasePtr pDbase = *(TFontDbaseHdl)fontDbase;
  1805.         
  1806.         pDbase->lockCount -= 1;
  1807.         
  1808.         if (pDbase->lockCount <= 0) {
  1809.         
  1810.             HUnlock((Handle)fontDbase);
  1811.  
  1812.             ncheck(pDbase->lockCount < 0);
  1813.             
  1814.             
  1815.         }//end if
  1816.         
  1817.         return(MemError());
  1818.     }
  1819.  
  1820.  
  1821. //<FF>
  1822. /***********************************************
  1823.  
  1824.     Routine:     FDBIncludeFont
  1825.     
  1826.     Routine checks to see if a font should be included
  1827.     based upon the hExclusionList.  The format of the exclusion
  1828.     list is a packed array of gxFlatFontName's, preceeded by 
  1829.     a long count.  If the list is nil, it means include all fonts.
  1830.     
  1831.     theFont:                    The font to see if should be included.
  1832.     hExclusionList:        Handle to the packed array of gxFlatFontName's
  1833.     include:                    (returned) include the font or not.
  1834.         
  1835. *************************************************/
  1836. OSErr FDBIncludeFont(gxFont theFont, Handle hExclusionList, Boolean *include);
  1837. OSErr FDBIncludeFont(gxFont theFont, Handle hExclusionList, Boolean *include)
  1838.     {
  1839.         OSErr                        status;
  1840.         long                        idx;
  1841.         long                        listSize;                    // number of entries in the list.
  1842.         unsigned char        *p;
  1843.         gxFlatFontName    *entry;                        // the current entry in the list.
  1844.         long                        nameSize;
  1845.         long                        biggestSize = 0;
  1846.         long                        nameIndex;
  1847.         Handle                    hName;
  1848.         
  1849.         if (hExclusionList == nil) {
  1850.         
  1851.             status = noErr;
  1852.             *include = true;
  1853.             
  1854.         } else { 
  1855.         
  1856.             HLock(hExclusionList);
  1857.         
  1858.             p = (unsigned char*)*hExclusionList;
  1859.             
  1860.             *include = true;
  1861.     
  1862.             /* get the number of items in the list */        
  1863.             listSize = *(long*)p;                
  1864.             p += sizeof(long);
  1865.             
  1866.             
  1867.             /** Search the list **/
  1868.             
  1869.             idx = 0;
  1870.             
  1871.             status = PrNewHandle(&hName, 0);                // allocate a zero size handle to start with for the name.
  1872.             nrequire(status, failed_Alloc);
  1873.             
  1874.             while (idx < listSize) {
  1875.             
  1876.                 entry = (gxFlatFontName*)p;
  1877.                 
  1878.                 if (GXFindFontName(theFont, entry->name, entry->platform, entry->script, entry->language,
  1879.                                                                             nil, &nameIndex) ) {
  1880.     
  1881.                     nameSize = GXGetFontName(theFont, nameIndex, nil, nil, nil, nil, nil);
  1882.                     
  1883.                     if (nameSize == entry->length) {            // only bother comparing if sizes are the same
  1884.                     
  1885.                         /* make sure handle is big enough for name */
  1886.                         
  1887.                         if (nameSize > biggestSize) {
  1888.                         
  1889.                             status = PrSetHandleSize(hName, nameSize);
  1890.                             nrequire(status, failed_resize);
  1891.                             biggestSize = nameSize;
  1892.                         
  1893.                         }//end if
  1894.                         
  1895.                         /* actually get the name */
  1896.                         
  1897.                         HLock(hName);
  1898.                         GXGetFontName(theFont, nameIndex, nil, nil, nil, nil, (unsigned char*)*hName);
  1899.                         HUnlock(hName);
  1900.                         
  1901.                         /* Now compare the name to the one from the resource */
  1902.                         
  1903.                         if (!memcmp(*hName, p + sizeof(gxFlatFontName), entry->length)) {
  1904.                             *include = false;
  1905.                             break;
  1906.                         }//end if
  1907.                         
  1908.                     }//end if
  1909.                     
  1910.                 }//end if
  1911.                 
  1912.                 p += sizeof(gxFlatFontName) + 4 * ((entry->length + 3) / 4);
  1913.                 ++idx;
  1914.             
  1915.             }//end do
  1916.  
  1917. failed_resize:
  1918.     
  1919.             DisposeHandle(hName);
  1920.             HUnlock(hExclusionList);
  1921.                 
  1922.         }//end if
  1923.  
  1924.  
  1925. failed_Alloc:
  1926.         return(status);
  1927.     
  1928.     }//FDBIncludeFont
  1929.  
  1930. /***********************************************
  1931.  
  1932.     Routine:        FontDbaseSpoolFonts
  1933.     
  1934.     Routine adds sfnt resources to the spool file for all document fonts.
  1935.     The resources are sparse fonts containing only the document required glyphs.
  1936.     Fonts get added to spool file as sfnt resources.
  1937.     
  1938.     fontDabse:                The font database
  1939.     theFile:                    The spool file reference
  1940.     justAppFonts:            true if you just want the application owned fonts, false for all fonts.
  1941.     hExclusionList:        The list of fonts to exclude from the spool file.
  1942.     useMessages:            use messages for adding resources, else use file handler directly.
  1943.     
  1944. *************************************************/
  1945. OSErr    FontDbaseSpoolFonts(TFontDbase fontDbase, gxSpoolFile* theFile, Boolean justAppFonts, Handle hExclusionList)
  1946.     {
  1947.         OSErr                            status;
  1948.         long                            numFonts;                        // How many fonts?
  1949.         long                            i;                                    // index for font
  1950.         gxFont                        fontRef;                        // Font to stream;
  1951.         unsigned long*        glyphBits;                    // bit array for font glyph usage.
  1952.         gxFontAttribute        theAttribute;                // "What kind of font are you?  I'm BatFont."
  1953.         Boolean                        includeFont;                // Should we include this font.
  1954.         Boolean                        systemFont;                    // is it a system font.
  1955.         long                            prereqCount;                // Number of prerequisite items for flattening.
  1956.  
  1957.         #if !GXTOPOSTSCRIPTLIBRARY
  1958.             /* Grabbing FONDs was only necessary for creating PDDs from non-GX apps */
  1959.             fontSfntMap**            fontList;                        // list of font records for grabbing FONDs for embedding
  1960.             long                            fontListCount;            // the number of records in fontList
  1961.         #endif
  1962.                 
  1963.         TFile                            fileRef;                        // a temporary file for partial streaming
  1964.         Handle                        hStream;                        // a temporary handle for partial streaming
  1965.         Collection                pictCollection;            // used to detect if there are no quickdraw shapes
  1966.                 
  1967.         status = FontDbaseLock(fontDbase);
  1968.         nrequire(status, failed_DbaseLock);
  1969.  
  1970.         status = FontDbaseCountFonts(fontDbase, &numFonts);
  1971.         nrequire(status, failed_CountFonts);
  1972.         
  1973.         #if !GXTOPOSTSCRIPTLIBRARY
  1974.             /* Grabbing FONDs was only necessary for creating PDDs from non-GX apps */
  1975.             status = PrNewHandle(&fontList, numFonts * sizeof(fontSfntMap));
  1976.             nrequire(status, failed_CountFonts);
  1977.             fontListCount = 0;
  1978.         #endif
  1979.         
  1980.         fileRef = nil; hStream = nil;
  1981.         
  1982.         for (i = 1; i <= numFonts; ++i) {
  1983.         
  1984.             status = FontDbaseGetIndexedFont(fontDbase, i, &fontRef);
  1985.             nrequire(status, failed_GetFont);
  1986.             
  1987.             /** Initialize the font info to exclude prerequisites **/
  1988.             
  1989.             status = FontDbaseExcludePrerequisite(fontDbase, fontRef, true);
  1990.             nrequire(status, failed_exclude1);
  1991.             
  1992.             // put the font in the file if either
  1993.             //  a) we are placing all fonts in the file and it is not in the exclusion list (or list is nil)
  1994.             //  b) the font is not a system font
  1995.     
  1996.             GXGetFont(fontRef, nil, &theAttribute);
  1997.  
  1998.             systemFont = (theAttribute & gxSystemFontAttribute) ? true : false;            
  1999.             includeFont = !systemFont;
  2000.             
  2001.             if (!justAppFonts && systemFont) {
  2002.             
  2003.                 status = FDBIncludeFont(fontRef, hExclusionList, &includeFont);
  2004.                 nrequire(status, failed_IncludeFont);
  2005.             
  2006.             }//end if
  2007.             
  2008.             if (includeFont) {
  2009.             
  2010.                 #if !GXTOPOSTSCRIPTLIBRARY
  2011.                     /* Grabbing FONDs was only necessary for creating PDDs from non-GX apps */
  2012.                     (*fontList)[fontListCount].fontID = fontRef;
  2013.                     (*fontList)[fontListCount].newSfntRsrcID = 128 + i;
  2014.                     ++fontListCount;
  2015.                 #endif
  2016.                 
  2017.                 /** Turn off exclusion of prerequisites **/
  2018.                 
  2019.                 status = FontDbaseExcludePrerequisite(fontDbase, fontRef, false);
  2020.                 nrequire(status, failed_exclude2);
  2021.                 
  2022.                 /** Get the bits **/
  2023.                 
  2024.                 status = FontDbaseGetGlyphBits(fontDbase, fontRef, 0, &glyphBits, nil);
  2025.                 nrequire(status, failed_GetBits);
  2026.         
  2027.                 /** We really need the file now if we don't have it **/
  2028.  
  2029.                 if (fileRef == nil)    {
  2030.                     status = CreatePartialStreamTempFile(&fileRef, &hStream);
  2031.                     nrequire(status, failed_CreateTempFile );
  2032.                 }
  2033.  
  2034.                 /** Make a handle **/
  2035.                 
  2036.                 status = FDBFontToHandle(fontRef, (long*)glyphBits, hStream);
  2037.                 nrequire(status, failed_FontToHandle);
  2038.     
  2039.                 // Important change:  Using spool file C++ object instead of GX messages.
  2040.                 status = theFile->SpoolResource(hStream, 'sfnt', 128 + i);
  2041.                 nrequire(status, failed_SpoolRes);
  2042.                 
  2043.             }//end if
  2044.             
  2045.         }//end for
  2046.  
  2047. #if !GXTOPOSTSCRIPTLIBRARY
  2048.     /* PICT COLLECTION STUFF WAS ONLY NECESSARY FOR COMPATIBILITY PRINTING */
  2049.  
  2050. /*
  2051.  *    If this collection exists, but it has no entries, then we know
  2052.  *    that we don't have any QD shapes, so we can skip the FONDs and NFNTs
  2053.  */
  2054.         status = SHGetPictCollection(theFile, &pictCollection);
  2055.         nrequire(status, failed_get_pict_collection);
  2056.         if ((pictCollection == nil || CountCollectionItems(pictCollection) > 0) && fontListCount > 0)
  2057.         {
  2058.                 Handle    FONDList;
  2059.                 long        FONDCount;
  2060.         
  2061.                 HLock((Handle)fontList);
  2062.                 status = FDBListOfReferencedFONDs(fontListCount, *fontList, &FONDCount, &FONDList);
  2063.                 nrequire(status, failed_list_of_referenced_fonds);
  2064.                 if (FONDCount > 0)
  2065.                 {        status = FDBAddFONDsToResourceFile(FONDCount, FONDList, theFile, useMessages);
  2066.                         nrequire(status, failed_add_fonds_to_resource_file);
  2067.                 }
  2068.         }
  2069. #endif
  2070.  
  2071. failed_get_pict_collection:
  2072. failed_list_of_referenced_fonds:
  2073. failed_add_fonds_to_resource_file:
  2074.  
  2075. #if !GXTOPOSTSCRIPTLIBRARY
  2076.         DisposeHandle((Handle)fontList);
  2077.  
  2078.         if (status != noErr)
  2079.                 goto failed_add_fonds;
  2080.  
  2081. #endif
  2082.  
  2083.         /********* Now stream out any required prerequisites ***********/
  2084.         
  2085.         
  2086.         {
  2087.             unsigned char                        prereqItemData[256 + sizeof(scalerPrerequisiteItem)];            // Can't be any bigger 'cause name is pascal string
  2088.             scalerPrerequisiteItem    *prereqItem = (scalerPrerequisiteItem*)prereqItemData;
  2089.             gxFont                                    aFont;
  2090.             short                                        theID;
  2091.     
  2092.             status = FontDbaseBuildPrerequisiteList(fontDbase, flattenedStreamType, nil, false, &prereqCount);
  2093.             nrequire(status, failed_buildPrereq);
  2094.     
  2095.             #if DEBUGLEVEL >= DEBUGFEEDBACK            
  2096.                 dprintf(trace, "# prerequisite items: %d", prereqCount);
  2097.             #endif
  2098.             
  2099.             for (i = 1; i <= prereqCount; ++i) {
  2100.             
  2101.                 status = FontDbaseGetIndexedPrerequisite(fontDbase, i, nil, &aFont, prereqItem);
  2102.                 nrequire(status, failed_getprereq);
  2103.                 
  2104.                 #if DEBUGLEVEL >= DEBUGFEEDBACK            
  2105.                     dprintf(trace, "Flattening prerequisite: %d for font: %d", prereqItem->enumeration, aFont);
  2106.                 #endif
  2107.                 
  2108.                 if (fileRef == nil)    {
  2109.                     status = CreatePartialStreamTempFile(&fileRef, &hStream);
  2110.                     nrequire(status, failed_CreateTempFile2 );
  2111.                 }
  2112.  
  2113.                 status = FDBPrereqToHandle(aFont, prereqItem, hStream);
  2114.                 nrequire(status, failed_prereqToHandle);
  2115.                 
  2116.                 theID = 128 + 10 + numFonts + i;            //  ID will start at 128 + 10 more than number of fonts.
  2117.  
  2118.                 // Change from sending gx message to using C++ class;    
  2119.                 status = theFile->SpoolResource(hStream, 'sfnt', theID);
  2120.                 nrequire(status, failed_SpoolPrereq);
  2121.     
  2122.                 /** Now name the resource with the prerequisite name so ATM can find it in the resource chain **/
  2123.                 {
  2124.                     Handle hFont = GetResource('sfnt', theID);            // Get it again, only try to name it if we succeeded.
  2125.                     if (hFont) {
  2126.                     
  2127.                         SetResInfo(hFont, theID, prereqItem->name);
  2128.  
  2129.                     }//end if
  2130.                 }
  2131.             
  2132.             }//end for
  2133.         
  2134.         }
  2135.             
  2136.  
  2137.         /*****************  Now reset the prerequisite exclusion flags *******************/
  2138.  
  2139.         for (i = 1; i <= numFonts; ++i) {
  2140.         
  2141.             /** Clear the flag to exclude prerequisites **/
  2142.             
  2143.             
  2144.             status = FontDbaseGetIndexedFont(fontDbase, i, &fontRef);
  2145.             nrequire(status, failed_GetFont2);
  2146.             
  2147.             status = FontDbaseExcludePrerequisite(fontDbase, fontRef, true);
  2148.             nrequire(status, failed_exclude3);
  2149.                         
  2150.         }//end for
  2151.         
  2152. failed_exclude3:
  2153. failed_GetFont2:
  2154.  
  2155. failed_SpoolPrereq:
  2156. failed_prereqToHandle:
  2157. failed_CreateTempFile2:
  2158. failed_getprereq:
  2159. failed_buildPrereq:
  2160.  
  2161. failed_add_fonds:
  2162.  
  2163. failed_SpoolRes:
  2164. failed_FontToHandle:
  2165. failed_CreateTempFile:
  2166. failed_GetBits:
  2167. failed_SetFlags1:
  2168. failed_exclude2:
  2169. failed_IncludeFont:
  2170. failed_exclude1:
  2171. failed_GetFont:
  2172.         {
  2173.             if( fileRef )
  2174.                 DisposePartialStreamTempFile( fileRef, hStream );
  2175.         }
  2176.  
  2177. failed_CountFonts:
  2178.         {
  2179.             OSErr            saveStatus = FontDbaseUnlock(fontDbase);
  2180.             if (status == noErr)
  2181.                 status = saveStatus;
  2182.                 
  2183.             ncheck(status);
  2184.         }
  2185.  
  2186. failed_DbaseLock:
  2187.  
  2188.         return(status);
  2189.         
  2190.     }//FontDbaseSpoolFonts
  2191.         
  2192.  
  2193.  
  2194.  
  2195.  
  2196. //<FF>
  2197. /*************************************
  2198.  
  2199.     Function: FontDbaseUnion
  2200.     
  2201.     Function makes a copy of a font database object.
  2202.     
  2203.     
  2204.     source:        Font database object to copy.
  2205.     target:        Union entries from source font database into this font database.
  2206.     
  2207. ***************************************/
  2208. OSErr FontDbaseUnion(TFontDbase source, TFontDbase target)
  2209.     {
  2210.         OSErr                                status, saveStatus;
  2211.         long                                index;
  2212.         TFontDbaseHdl                hSource;
  2213.         Collection                    sourceOffsets;
  2214.         long                                offset;
  2215.         gxFlatFontListItem    *sourceItem;
  2216.         unsigned char             *p;
  2217.         Boolean                            useMac8bitEncoding;
  2218.         
  2219.         status = FontDbaseLock(source);
  2220.         nrequire(status, failed_Lock);
  2221.         
  2222.         hSource = (TFontDbaseHdl)source;
  2223.         
  2224.         sourceOffsets = (*hSource)->docFonts;
  2225.         
  2226.         for (index = 1; index <= (*hSource)->numFonts; ++index) {
  2227.  
  2228.             status = GetIndexedCollectionItem(sourceOffsets, index, nil, &offset);
  2229.             nrequire(status, failed_GetItem);
  2230.             
  2231.             p = (unsigned char*)((*hSource)->fontDbaseInfo) + offset;     // Point to entry.
  2232.  
  2233.             if ( ((TFDBEntry*)p)->flags & fdbUseMac8Bit)
  2234.                 useMac8bitEncoding = true;
  2235.             else
  2236.                 useMac8bitEncoding = false;
  2237.                 
  2238.             sourceItem = &( ((TFDBEntry*)p)->fontInfo);
  2239.         
  2240.             status = FontDbaseAddItem(target, sourceItem, useMac8bitEncoding);
  2241.             nrequire(status, failed_AddItem);
  2242.         
  2243.         }//end for
  2244.         
  2245. failed_AddItem:
  2246. failed_GetItem:
  2247. failed_Lock:
  2248.         saveStatus = FontDbaseUnlock(source);
  2249.         if (status == noErr)
  2250.             status = saveStatus;
  2251.             
  2252.         return(status);
  2253.         
  2254.     }//FontDbaseUnion
  2255.  
  2256.